package cn.wei.youvierpc.server.tcp;

import cn.hutool.core.util.IdUtil;
import cn.wei.youvierpc.model.RpcRequest;
import cn.wei.youvierpc.model.RpcResponse;
import cn.wei.youvierpc.model.ServiceMetaInfo;
import cn.wei.youvierpc.protocol.*;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetClient;
import io.vertx.core.net.NetSocket;

import java.io.IOException;
import java.security.Provider;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class VertxTcpClient {

    public void start() {
        Vertx vertx = Vertx.vertx();
        vertx.createNetClient().connect(8888, "localhost", netSocketAsyncResult -> {
            if (netSocketAsyncResult.succeeded()) {
                System.out.println("Connected to tcp server");
                NetSocket socket = netSocketAsyncResult.result();

                socket.write("hello, server");
                socket.handler(buffer -> {
                    System.out.println("response : " + buffer.toString());
                });
            } else {
                System.out.println("failed to connect tcp server");
            }
        });
    }


    public static RpcResponse doRequest(RpcRequest request, ServiceMetaInfo serviceMetaInfo) throws ExecutionException, InterruptedException {
        Vertx vertx = Vertx.vertx();
        NetClient netClient = vertx.createNetClient();

        CompletableFuture<RpcResponse> responseFuture = new CompletableFuture<>();
        netClient.connect(serviceMetaInfo.getServicePort(), serviceMetaInfo.getServiceHost(),
                netSocketAsyncResult -> {
                    if (netSocketAsyncResult.succeeded()) {
                        System.out.println("connected to tcp server!");
                        NetSocket socket = netSocketAsyncResult.result();
                        ProtocolMessage<RpcRequest> rpcRequestProtocolMessage = new ProtocolMessage<>();
                        ProtocolMessage.Header header = new ProtocolMessage.Header();
                        header.setMagic(ProtocolConstant.PROTOCOL_MAGIC);
                        header.setVersion(ProtocolConstant.PROTOCOL_VERSION);
                        header.setSerializer((byte) ProtocolMessageSerializerEnum.JDK.getKey());
                        header.setType((byte) ProtocolMessageTypeEnum.REQUEST.getKey());
                        header.setStatus((byte) ProtocolMessageStatusEnum.OK.getValue());
                        header.setRequestId(IdUtil.getSnowflakeNextId());
                        rpcRequestProtocolMessage.setBody(request);
                        rpcRequestProtocolMessage.setHeader(header);

                        Buffer requestBuffer = null;
                        try {
                            requestBuffer = ProtocolMessageEncoder.encode(rpcRequestProtocolMessage);
                        } catch (IOException e) {
                            throw new RuntimeException("协议消息编码失败");
                        }
                        socket.write(requestBuffer);

                        TcpBufferHandlerWrapper bufferHandlerWrapper = new TcpBufferHandlerWrapper(buffer -> {
                            try {
                                ProtocolMessage<RpcResponse> responseProtocolMessage = (ProtocolMessage<RpcResponse>) ProtocolMessageDecoder.decode(buffer);
                                responseFuture.complete(responseProtocolMessage.getBody());
                            } catch (IOException e) {
                                throw new RuntimeException("协议消息解码出错");
                            }
                        });

                        socket.handler(bufferHandlerWrapper);
                    } else {
                        System.out.println("failed to connect to tcp server");
                    }
                });
        RpcResponse rpcResponse = responseFuture.get();
        netClient.close();

        return rpcResponse;
    }

    public static void main(String[] args) {
        new VertxTcpClient().start();
    }
}
